<?php

/*
* teia\webdev\php\core\
* Pool of utility functions
*
* @author Bernardo Quibiana
* @date created: 20111017
*
* @date modified: 20111018
* @modified: Bernardo Quibiana
*/

// namespace declaration: Core Utilities
namespace teia\webdev\php\core;

require_once 'SessionWrapper.inc';
require_once 'TypePool.inc';

$inc_recaptcha = realpath(dirname(__FILE__) . '/../plugin/recaptcha/recaptchalib.php');
require_once $inc_recaptcha;

class FunctionPool {
	
	/*
	 * Object functions
	 */
	
	static function set_obj_properties(&$obj, $var_array) {
		if ($var_array && is_array($var_array)) {
			foreach ($var_array as $key => $value) {
				@$obj->$key = $value;
			}
		}	
	}
	
	/**
	 * Check whether all elements of a specified array are instance of a specfied class
	 * @param array $array
	 * @param class $class
	 * @return boolean
	 */
	static function check_elements_class($array, $class) {
		$pass = false;
		foreach ($array as $obj) {
			// ($obj instanceof $class)
			if (!is_a($obj, $class)) {
				return false;	
			}
			$pass = true;	// the loop must run at least once
		}
		return $pass;
	}
		
	/*
	 * Array functions
	 */
	
	static function array_count($array) {
		$count = 0;
		foreach ($array as $value) {
			if (is_array($value)) {
				$count += self::array_count($value);
			} else {
				$count += empty($value) ? 0 : 1;
			}
		}
		return $count;
	}
	
	static function array_empty($array) {
		$count = self::array_count($array);
		return ($count == 0);
	}
	
	/**
	 * Return an element from the specified array
	 * @param array $array target array
	 * @param boolean $first whether to return the first element of the array
	 * @return mixed|Ambiguous an element from the array; If $first is set to true, return the first
	 * element or false on failure, otherwise return the current element or a random element on failure.
	 */
	static function array_peek($array, $first=TRUE) {
		if ($first) {
			return reset($array);
		}
		$current = current($array);
		if ($current === FALSE) {
			$key = array_rand($array, 1);
			return $array[$key];
		}
		return $current;
	}
	
	static function array_single($array) {
		$count = count($array);
		if ($count == 1) {
			return $array[0];
		} else {
			return $array;
		}
	}
	
	static function array_limit($array, $max_size) {
		$target = array();
		$count = 0;
		foreach ($array as $key => $value) {
			if ($count < $max_size) {
				$target[$key] = $value;
			} else {
				break;
			}
		}
		return $target;
	}
	
	static function array_empty_value($array) {
		foreach ($array as $value) {
			if (empty($value))
				return true;
		}
		return false;
	}
	
	/**
	 * Search an array for values in a given array
	 * @param array $needles array of target values
	 * @param array $haystack array to be searched
	 * @param boolean $strict whether to search for identical elements in the haystack
	 * @return mixed if successful return an array with the corresponding indexes of the target values, 
	 * otherwise return false
	 */
	static function array_search($needles, $haystack, $strict=FALSE) {
		$keys = array();
		foreach ($needles as $needle) {
			$needle_key = array_search($needle, $haystack, $strict);
			if ($needle_key === false) {
				// echo "first failure: $needle\n";
				return false;
			}
			array_push($keys, $needle_key);
		}
		return $keys;
	}
	
	
	static function array_to_str($array, $delim = ' ', $marker = '') {
		$str = "";
		foreach ($array as $value) {
			$str .=  $marker . $value . $marker . $delim;
		}
		return trim($str, $delim);	// remove last delimiter and return
	}
	
	static function array_to_assoc($array, $num_keys=TRUE) {
		$assoc = array();
		if ($num_keys) {
			foreach ($array as $key => $value) {
				$assoc[$key] = $value;
			}
		} else {
			foreach ($array as $value) {
				$assoc[$value] = $value;
			}
		}
		return $assoc;
	}
	
	/**
	 * Formats an associative array into a string
	 * @param array $array the subject associative array to format
	 * @param string $delim string to delimiter array elements (elem 'delim' elem, each elem is a pair of key-value)
	 * @param string $marker string to delimiter values ('marker' $value 'marker')
	 * @param string $ptr string to separate key and value ($key 'ptr' $value)
	 * @return string return a formatted string of the form 'empy | elem ['delim' elem]*', where elem => '$key 'ptr' 'marker' $value 'marker''
	 */
	static function assoc_to_str($array, $delim = ' ', $marker = '"', $ptr= '=') {
		$str = '';
		if (is_array($array)) {
			foreach ($array as $key => $value) {
				$str .= $key . $ptr . $marker . $value . $marker . $delim;
			}
		}
		return trim($str, $delim);	// remove last delimiter and return
	}
	
	static function assoc_prepend($array, $key, $value) {
		$pre = array($key => $value);
		return array_merge($pre, $array);
	}
	/*
	 * Miscellaneous
	 */
	
	/**
	 * Bounds a value in an interval specified by a minimum and a maximum
	 * @param number $val the value to bound
	 * @param number $min the minimum value allowed (lower bound)
	 * @param number $max the maximum value allowed (upper bound)
	 * @throws Exception throws an Exception if the lower bound is not strictly less than the upper bound
	 * @return number return the value if it is in the bounding interval, 
	 * or return the minimum if the value is less than the lower bound, 
	 * or return the maximum if the value is greater than the upper bound
	 */
	static function clamp($val, $min, $max) {
		if ($min > $max) {
			throw  new \InvalidArgumentException('Invalid arguments: expected minimum to be less than maximum');
		}
		if ($val < $min) {
			return $min;
		} elseif ($val > $max) {
			return $max;
		}
		return $val;
	}
	
	/**
	 * Check if all specified vars are set in $_POST[] and if they are empty
	 * @param array $vars array with names of the variables to check
	 * @return boolean return true if all variables are set and none is empty
	 */
	static function validate_request_vars($vars) {
		foreach ($vars as $var) {
			if (!isset($_REQUEST[$var]) ||  empty($_REQUEST[$var])) {
				return false;
			}
		}
		return true;
	}
	
	/**
	*
	* @param string $date_str
	* @return string
	*/
	static function validate_date_str($date_str, $out_format='Y-m-d') {
		date_default_timezone_set(DEFAULT_TIME_ZONE);
		$timestamp = strtotime($date_str);
		$date = date($out_format, $timestamp);
		
		return $date;
	}
	
	static function password_check($password_1, $password_2, $min_len=MIN_PWD_LENGTH, $max_len=MAX_PWD_LENGTH, $pattern=PWD_REGEX) {
		$len = strlen($password_1);
		
		if ($len < $min_len)
			return PasswordCheck::TOO_SHORT;
		elseif ($len > $max_len)
			return PasswordCheck::TOO_LONG;
		elseif (preg_match($pattern, $password_1) == 0)
			return PasswordCheck::PATTERN_MISMATCH;
		elseif (strcmp($password_1,$password_2) != 0)
			return PasswordCheck::REPETITION_MISMATCH;
		else 
			return PasswordCheck::PASS;
	}
	
	static function parse_csv_file($path, $mode='r', $length=0, $delimiter=',', $enclosure='"', $escape='\\') {
		$csv = null;
		if (($handle = fopen($path, $mode)) !== FALSE) {
			$csv = array();
			while (($row = fgetcsv($handle, $length, $delimiter, $enclosure, $escape)) !== FALSE) {
				array_push($csv, $row);
			}
			fclose($handle);
		}
		return $csv;
	}
	
	/*
	 * Email functions
	 */
	
	static function validate_email($email) {
		$email_pattern ='#^[a-zA-Z0-9_\.\-]+@[a-zA-Z0-9\-]+\.[a-zA-Z0-9\-\.]+$#';
		if (preg_match($email_pattern, $email) != 0) {
			return true;
		} else {
			return false;
		}
	}

	/*
	 * Captcha 
	 */
	
	static function display_recaptcha($pub_key=RECAPTCHA_PUB_KEY, $err = NULL) {
		echo recaptcha_get_html($pub_key, $err);
	}
	
	/**
	 * Enter description here ...
	 * @param string $challenge
	 * @param string $response
	 * @param string $priv_key
	 * @return boolean
	 */
	static function verify_recaptcha_response($challenge, $response, $priv_key=RECAPTCHA_PRIV_KEY) {
		$server = $_SERVER['SERVER_NAME'];
		//echo "priv key: $priv_key on " . $server . " <br />\n";
		//echo "verify: $challenge VS $response <br />\n";
		$resp = recaptcha_check_answer ($priv_key, $server, $challenge, $response);
				
		return $resp->is_valid;
	}
	/*
	 * Template display functions
	 * 
	 */
	
	/**
	 * Display a specified template by importing the PHP file
	 * @param string $url the url pointing to the template PHP file
	 * @param string[] $var_array associative string array containing the values for variables used in the template
	 */
	static function display_template($url, $var_array=NULL) {
		if ($var_array && is_array($var_array)) {
			foreach ($var_array as $key => $value) {
				$$key = $value;
				//echo "DEBUG: FunctionPool::display_template() >>\t$key = $value";
			}
		}
		require $url;
	}
	
	/**
	 * Display user log in form using the template login_form_inc
	 * @param string[] $txt_array associative string array containing the text for displayble form field names
	 */
	static function display_login_form($txt_array=NULL) {
		self::display_template('login_form.inc', $txt_array);
		//require 'login_form.inc';
	}
	
	/**
	* Display user sign-up form using the template signup_form_inc
	* @param string[] $txt_array associative string array containing the text for displayble form field names
	*/
	static function display_signup_form($txt_array=NULL) {
		self::display_template('signup_form.inc', $txt_array);
	}
	
	/**
	* Display user navigation message using the template usr_nav_msg.inc
	* @param string[] $txt_array associative string array containing the values for variables used in the template
	*/
	static function display_usr_nav_msg($txt_array=NULL) {
		self::display_template('usr_nav_msg.inc', $txt_array);
	}

	static function display_pwd_req_form($txt_array=NULL) {
		self::display_template('pwd_recaptcha_form.inc', $txt_array);
	}
	
	/*
	 * HTML templates 
	 */
	
	static function include_jquery($url=NULL) {
		if ($url && is_file($url)) {
			echo "<script type=\"text/javascript\" src=\"$url\"></script>";
		} else {
			echo "<script type=\"text/javascript\" src=\"http://code.jquery.com/jquery-latest.pack.js\"></script>\n";
		}
	}
	
	
	/**
	 * Write keywords using the meta element
	 * @param array $keywords string array of keywords 
	 */
	static function display_meta_keywords($keywords) {
		$keywords_str = self::array_to_str($keywords, ', ');
		echo '<meta name="keywords" content="' . $keywords_str . '" />\n';	
	}
	
	/**
	 * Write the page description using the meta element (should be less than 155 chars, relevant to search engines!)
	 * @param string $description description of the page content in plain text
	 */
	static function display_meta_description($description) {
		echo '<meta name="description" content="' . $description . '" />\n';
	}
	
	/**
	 * Write the search engine robot options using the meta element
	 * @param array $values 
	 */
	static function display_meta_robots($values) {
		$robots_str = self::array_to_str($values, ',');
		echo '<meta name="robots" content="' . $robots_str. '" />\n';
	}
	
	/**
	 * Write the author name using the meta element
	 * @param string $author name of the web developer in plain text
	 */
	static function display_meta_author($author='Teia - Web Development') {
		echo '<meta name="author" content="' . $author. '" />\n';
	}
	
	static function display_meta_charset($charset='UTF-8') {
		echo '<meta charset="' . $charset. '" />\n';
	} 
	
	static function display_meta($var_array) {
		if ($var_array && is_array($var_array)) {
			foreach ($var_array as $key => $value) {
				$$key = $value;
			}
		}
		
		if (!isset($author)) $author = 'Teia - Web Development';
		self::display_meta_author($author);
		
		if (isset($description)) self::display_meta_description($description);
		if (isset($keywords)) self::display_meta_keywords($keywords);
		if (isset($robots)) self::display_meta_robots($robots);
		if (!isset($charset)) $charset = 'UTF-8';
		self::display_meta_charset($charset);
	}
	
	/**
	 * Include AddThis toolbar, from www.addthis.com, for sharing in Facebook, Tweeter and others
	 * @param int $style_num style number (three styles are available)
	 */
	static function include_addthis_toolbar($style_num=1) {
		echo "<!-- AddThis Button BEGIN -->";
		switch ($style_num) {
			case 1:
				echo 
"<div class=\"addthis_toolbox addthis_default_style \">
	<a class=\"addthis_button_preferred_1\"></a>
	<a class=\"addthis_button_preferred_2\"></a>
	<a class=\"addthis_button_preferred_3\"></a>
	<a class=\"addthis_button_preferred_4\"></a>
	<a class=\"addthis_button_compact\"></a>
	<a class=\"addthis_counter addthis_bubble_style\"></a>
</div>
<script type=\"text/javascript\" src=\"http://s7.addthis.com/js/250/addthis_widget.js#pubid=xa-4ea870e5298c5b10\"></script>";
				break;
			case 2:
				echo 
"<div class=\"addthis_toolbox addthis_default_style addthis_32x32_style\">
	<a class=\"addthis_button_preferred_1\"></a>
	<a class=\"addthis_button_preferred_2\"></a>
	<a class=\"addthis_button_preferred_3\"></a>
	<a class=\"addthis_button_preferred_4\"></a>
	<a class=\"addthis_button_compact\"></a>
	<a class=\"addthis_counter addthis_bubble_style\"></a>
</div>
<script type=\"text/javascript\" src=\"http://s7.addthis.com/js/250/addthis_widget.js#pubid=xa-4ea871344e65747b\"></script>";
				break;	
			default:
				echo 
"<div class=\"addthis_toolbox addthis_default_style \">
	<a class=\"addthis_button_facebook_like\" fb:like:layout=\"button_count\"></a>
	<a class=\"addthis_button_tweet\"></a>
	<a class=\"addthis_button_google_plusone\" g:plusone:size=\"medium\"></a>
	<a class=\"addthis_counter addthis_pill_style\"></a>
</div>
<script type=\"text/javascript\" src=\"http://s7.addthis.com/js/250/addthis_widget.js#pubid=xa-4ea871520a7cb528\"></script>";
				break;
		}
		echo "<!-- AddThis Button END -->";
	}
	
	/*
	 * Navigation functions
	 */
	
	/**
	 * Get the filename of the currently executing script, relative to the document root, stored in $_SERVER['PHP_SELF']. 
	 * Encode the HTML elements in $_SERVER['PHP_SELF'] to prevent Cross Site Scripting (XSS) exploits.
	 * @return string the value of $_SERVER['PHP_SELF'] with HTML elements encoded
	 */
	static function get_php_self() {
		return htmlentities($_SERVER['PHP_SELF']);
	}
	
	static function get_query_array() {
		$query_array = array();
		$queries = explode("&",$_SERVER['QUERY_STRING']);
		foreach ($queries as $query) {
			$parts = explode('=', $query, 2);
			if ($parts !== FALSE && count($parts) == 2) {
				$query_array[$parts[0]] = $parts[1];
			}
		}
		
		return $query_array;
	}
	
	static function get_request_url($script=NULL, $queries=NULL, $ignore_old=FALSE) {
		if (is_null($script)) {
			$script = self::get_php_self();
		}
		if (is_null($queries)) {
			$queries = array();
		}
		$old_queries = $ignore_old ? array() : self::get_query_array();
		$all_queries = array_merge($old_queries, $queries);
		$query_str = self::encode_url_query($all_queries);

		if (strlen($query_str) > 2) {
			return $script . '?' . $query_str;
		} else {
			return $script;
		}
	}
	
	/**
	* Redirect the browser to a specified URL
	* @param string $url the target URL (default: /, home directory)
	* @param array $queries associative array of query data
	* @param boolean $exit whether to exit the current script after redirection (default: TRUE, exit script)
	*/
	static function goto_url($url='/', $queries=NULL, $exit=TRUE) {
		if ($queries) {
			$url .= '?' . self::encode_url_query($queries);
		}
		header("Location: $url");
		if ($exit) {
			exit();
		}
	}
	
	static function encode_url_query($queries) {
		return _recaptcha_qsencode($queries);
	}
	
	/**
	 * Redirect the current request for HTTPS access
	 */
	static function force_https_access() {
		if ($_SERVER['HTTPS'] != 'on') {
			// prepare https url
			$url = "https://" . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
			// redirect
			self::goto_url($url);
		}		
	}
}

?>